package com.tengju.bff.interfaces.covercharge.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tengju.bff.interfaces.covercharge.constant.AdminRoleEnum;
import com.tengju.bff.interfaces.covercharge.constant.DesensitionFieldType;
import com.tengju.bff.interfaces.covercharge.service.IRoleDesensitService;
import com.tengju.bff.interfaces.covercharge.annotation.RoleDesensit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: xx
 * @Description: 根据角色脱敏服务实现类
 * @Date: 2020/11/25 14:15
 */
@Slf4j
@Service
public class RoleDesensitServiceImpl implements IRoleDesensitService {

//    @Resource
//    private RoleServiceFacade roleServiceFacade;

    /**
     * 财务角色title编码长度
     */
    private final static Integer APP_FINANCE_LENGTH = 11;

    /**
     * 身份证角色title编码长度
     */
    private final static Integer APP_IDENTITY_LENGTH = 12;

    /**
     * 对结果List根据权限做脱敏处理
     *
     * @param page 查询结果
     * @return Page
     */
    @Override
    public Page checkDesensit(Page page, String appCode, Long ssoUserId) {
        //1、先判断page是否为空，是否有查询结果记录
        if (page == null || page.getRecords() == null) {
            return page;
        }
        //2、获得该用户角色
        List<String> roleList = getUserRoleCode(appCode, ssoUserId);
        //3、对查询结果脱敏
        page.setRecords(roleDesensit(page.getRecords(), roleList, ssoUserId));
        return page;
    }

    /**
     * 对结果List根据权限做脱敏处理
     *
     * @param list      需要脱敏list
     * @param appCode   应用appCode
     * @param ssoUserId sso用户id
     * @return 脱敏后记录
     */
    @Override
    public List checkDesensit(List list, String appCode, Long ssoUserId) {
        //1、先判断list是否为空，是否有查询结果记录
        if (CollectionUtil.isEmpty(list)) {
            return list;
        }
        //2、获得该用户角色
        List<String> roleList = getUserRoleCode(appCode, ssoUserId);
        //3、对查询结果脱敏
        return roleDesensit(list, roleList, ssoUserId);
    }

    /**
     * 获取用户角色codeList
     *
     * @param appCode   应用code
     * @param ssoUserId sso用户id
     * @return 返回角色code
     */
    public List<String> getUserRoleCode(String appCode, Long ssoUserId) {
        try {
            //TODO 权限
            if( 1 == 1){
                return new ArrayList<>();
            }

            //1、会先通过sso的用户id和应用的appcode调用sso基础服务获取该用户所分配的角色idList
//            JsonResult<List<Long>> jsonResult = roleServiceFacade.getRoleIdsByUserId(appCode, ssoUserId);
//            if (jsonResult == null || jsonResult.getCode() != 0 || CollectionUtil.isEmpty(jsonResult.getData())) {
//                return new ArrayList<>();
//            }
//            List<String> roleCodeList = new ArrayList<>();
//            for (Long roleId : jsonResult.getData()) {
//                //2、根据角色id获取角色code
//                JsonResult<RoleDTO> roleCodeResult = roleServiceFacade.get(roleId);
//                if (roleCodeResult == null || roleCodeResult.getCode() != 0 || CollectionUtil.isEmpty(jsonResult.getData())) {
//                    continue;
//                }
//                roleCodeList.add(roleCodeResult.getData().getCode());
//            }
//            return roleCodeList;
        } catch (Exception e) {
            log.error("[公共脱敏处理][调用sso基础服务平台][获取用户权限codeList失败]失败原因：", e);
            return new ArrayList<>();
        }
        return new ArrayList<>();
    }

    /**
     * 通过反射获取带注解的值,然后去做脱敏
     *
     * @param objectList 需要脱敏的对象
     * @param roleList   角色list
     * @return 返回处理后的对象
     */
    public List roleDesensit(List<?> objectList, List<String> roleList, Long ssoUserId) {
        //list为空,直接返回
        if (CollectionUtil.isEmpty(objectList)) {
            return objectList;
        }
        for (Object object : objectList) {
            // 首先通过反射获取object对象的类有哪些字段
            Field[] fields = object.getClass().getDeclaredFields();
            // for循环逐个字段校验，看哪个字段上标了注解
            for (Field field : fields) {
                // if判断：检查该字段上有没有标注了@RoleDesensit注解
                if (field.isAnnotationPresent(RoleDesensit.class)) {
                    // 通过反射获取到该字段上标注的@RoleDesensit注解的详细信息
                    RoleDesensit roleDesensit = field.getAnnotation(RoleDesensit.class);
                    DesensitionFieldType type = roleDesensit.type();
                    // 让我们在反射时能访问到私有变量
                    field.setAccessible(true);
                    String value;
                    try {
                        // 用过反射获取字段的实际值
                        value = ((String) field.get(object));
                        //拿着value，角色roleList,脱敏类型去做脱敏
                        field.set(object, desensit(value, roleList, type, ssoUserId));
                    } catch (Exception e) {
                        log.error("[公共脱敏处理][根据反射获取值失败][失败原因]", e);
                    }
                }
            }
        }
        return objectList;
    }

    public String desensit(String value, List<String> roleList, DesensitionFieldType type, Long ssoUserId) {
        if (StringUtils.isBlank(value)) {
            return value;
        }
        for (String role : roleList) {
            //判断是否有身份证号码权限
            if (DesensitionFieldType.IDENTITY_NO.getType().equals(type.getType())) {
                //判断是否有身份证权限
                if ((role.length() >= APP_IDENTITY_LENGTH) && (AdminRoleEnum.PAY_IDENTITY_TITLE.getCode().equals(role.substring(0, 12)))) {
                    //操作日子记录
                    log.info("[公共脱敏处理][该用户拥有身份证权限,正在查看身份证信息][该用户ssoUserId:{}]", ssoUserId);
                    return value;
                }
                continue;
            }
            //其它字段判断是否有财务权限，有则不脱，没有则脱
            //1、角色code是否大于指定值
            if ((role.length() >= APP_FINANCE_LENGTH) && (AdminRoleEnum.PAY_FINANCE_TITLE.getCode().equals(role.substring(0, 11)))) {
                log.info("[公共脱敏处理][该用户拥有财务权限,正在查看信息字段类型：{}][该用户ssoUserId:{}]", type, ssoUserId);
                return value;
            }
        }
        //没有则根据公共规则脱敏
        try {
            value = dealData(value, type.getType());
        } catch (Exception e) {
            log.error("[公共脱敏处理][脱敏失败,有异常抛出]原脱敏值:{},脱敏类型:{},失败原因:" + value, type, e);
        }
        return value;

    }

    /**
     * 公共脱敏方法
     *
     * @param value 需要脱敏的值
     * @param type  脱敏类型
     * @return 返回脱敏后的字符串
     */
    static String dealData(String value, String type) {
        //判断长度是否为2，若为2则认为是姓名，只脱最后一位
        if (DesensitionFieldType.NAME.getType().equals(type)) {
            if (value.length() > 2) {
                return StringUtils.left(value, 1).concat(StringUtils.leftPad(StringUtils.right(value, 1), StringUtils.length(value) - 1, "*"));
            }
            return value.substring(0, 1) + "*";
        } else if (DesensitionFieldType.MOBILE.getType().equals(type) || DesensitionFieldType.IDENTITY_NO.getType().equals(type)) {
            if (value.startsWith("+")) {
                return StringUtils.left(value, 5).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 5, "*"));
            }
            //国外手机号
            return StringUtils.left(value, 3).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 3, "*"));
        } else if (DesensitionFieldType.BANKCARD_NO.getType().equals(type)) {
            //银行卡号处理
            return StringUtils.left(value, 6).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 6, "*"));
        } else if (DesensitionFieldType.COMPANY_ADDRESS.getType().equals(type)) {
            //公司地址处理
            return StringUtils.rightPad(StringUtils.left(value, 3), StringUtils.length(value), "*");
        } else if (DesensitionFieldType.DUTY_PARAGRAPH.getType().equals(type)) {
            //税号处理
            return "****";
        }
        return value;
    }
}
